Intro to MDX
This blog uses a key bit of technology we haven't yet learned about: MDX. It's an absolutely indispensable tool when it comes to creating interactive content.
Let's learn about it.
Video Summary
When we want to build a content-heavy site, like a blog or technical documentation, we have to make a decision: will we treat the content itself as code or data.
To explain what I mean by that, let's take a look at the very first version of my blog, circa 2018:
Overall, this design hasn't aged particularly well in my opinion, but there is one thing I like: the green swoops flatten out as you scroll up:
The very first blog post I wrote, when I built this blog post in 2018, is about this effect. It includes embedded demos like this:
In this project, the content is treated as code. Here's what it looks like:
// src/components/DynamicBezierCurve.jsfunction DynamicBezierCurves() { return ( <> <p> First off - woohoo! This is my first published post on the new blog. I'm super excited. Thanks for checking it out! 🥂 </p>
<p> While building this blog, I wanted it to feel whimsical, with plenty of charming interactions and animations. I built this while working on my React Europe talk,{' '} <TextLink href="https://www.youtube.com/watch?v=Z2d9rw9RwyE"> The Case for Whimsy </TextLink> , and so it was very much on my mind. </p>
<p> In this maiden blog post, we'll go through the basics of working with Bézier curves and SVG in React.js. We'll learn how to build dynamic curves that respond to user input: </p>
<SingleAxisDemo id="flattenable-curve" showNote={true} defaultValue={20} > {(value) => ( <InitialCurve percentStraightened={value} color={COLORS.pink[500]} /> )} </SingleAxisDemo>
<Divider /> <SectionHeading anchorId="understanding-svg-paths"> A Quick SVG Refresher </SectionHeading> <p> For achieving this effect, we'll use SVG. We could also use HTML Canvas, but I generally prefer to work with SVG. It's more React-like in its API, there's less complexity in setting it up, and it's more a11y-friendly. </p> {/* ✂️ content trimmed for brevity */} </> );}
Each blog post gets its own massive component; the real version of this component is >700 lines long!
By writing the blog post in JSX, I have a ton of flexibility. I can do anything I'd do in any other React context! The full power of React and JavaScript is available to me. This is how I'm able to embed components like SingleAxisDemo
.
But creating content this way has two big downsides:
First, the authoring experience is dreadful. It's so much extra syntax! Having to include all of the closing tags and deal with JSX peculiarities like {' '}
gets really tiresome.
Also, and this one is a bit more subtle: there's no way to “aggregate” or collect the data for the blog posts.
Most blog posts have an index page where we list all of the posts:
With the first version of my blog, I had to hardcode this list of posts, editing the index.js
to include another list item for the newest post. Ideally, this list should be dynamically created for me, based on the content.
Alternatively, we can treat the content as data.
One way to do this would be to use a like WordPress or Contentful. Another way would be to use Markdown.
Markdown is a markup language. We've been using it for the README.md
files in the projects. It looks like this:
Markdown is meant to compile to HTML. The syntax corresponds to HTML tags.
It's designed to offer a nicer authoring experience by having minimal syntax. Paragraphs are created automatically. Symbols are used to enable tags with less typing (for example, **note**
is much shorter than <strong>note</strong>
).
Markdown also includes a way to store metadata about the post, using frontmatter. This is the data at the top of the file that lets us store things like the blog post's title and publication date.
The big downside is that we're limited to a handful of built-in HTML tags. We can render images and lists and tables, but there's no way to create custom embedded widgets, like the SingleAxisDemo
:
But what if we could include React components within our Markdown files? 🤔
This is exactly what we get with MDX. It's a superset of Markdown: every valid Markdown document is also a valid MDX document. The only difference is that with MDX, we can render any JSX we want. It's MarkDown + JSX.
This is the best of both worlds. We have the delightful authoring experience of Markdown and the full power of React. It's honestly pretty magical, and I can't imagine trying to build a blog without it.
How does it work though? It depends on the MDX implementation. We'll learn more about this in the next lesson.